package tp1POO.Modelo;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Vector;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import tp1POO.Persistencia.FileManager;
import tp1POO.Persistencia.GerenciadorObjetos;

@IdClass(LocacaoPK.class)
@Entity
public class Locacao extends ObjetoPOO implements Serializable
{
	/**Construtor padrão
	 *
	 * Inicializa todas os atributos da clase Locacao
	 */
	private Locacao() {
		//Inicializacao
		kmSaida = 0;
		kmEntrada = 0;
		valor = 0;
		previsaoDias = 0;
		tipoLocacao = "";
		locador = null;
		veiculo = null;
	}

	/**Construtor que inicializa o veículo e o cliente da locação
	 *
	 * @param parVeiculo Veiculo - Veiculo a ser adicionado na locação
	 * @param parLocador Cliente - Cliente que fará a locação
	 */
	public Locacao(Veiculo parVeiculo, Cliente parLocador)
	{
		this();
		this.motoristas = new Vector<Motorista>();
		this.dataDevolucao = new GregorianCalendar();
		this.dataSaida = new GregorianCalendar();

		setVeiculo(parVeiculo);
		setLocador(parLocador);
	}

	/**
	 * Construtor que inicializa o veículo, o cliente e o motorista
	 *
	 * @param parVeiculo  Veiculo - Veículo a ser adicionado na locação
	 * @param parLocador Cliente - Cliente que fará a locação
	 * @param parMotorista Motorista - Motorista a ser adicionado na locação
	 */
	public Locacao(Veiculo parVeiculo, Cliente parLocador, Motorista parMotorista)
	{
		this(parVeiculo, parLocador);
		addMotorista(parMotorista);
	}

	/**
	 * Método de retorno da quilometragem de saída
	 * @return Integer - quilometragem de saída
	 */
	public Integer getKmSaida() {
		return kmSaida;
	}

	/**
	 * Método para atribuir valor ao quilômetro de saída
	 * @param kmSaida Integer - quilometragem a ser atribuída
	 */

	public void setKmSaida(Integer kmSaida) {
		this.kmSaida = kmSaida;
	}

	/**
	 * Método de retorno da quilometragem de entrada
	 * @return Integer - quilometragem de entrada
	 */
	public Integer getKmEntrada() {
		return kmEntrada;
	}

	/**
	 * Método para atribuir valor a quilometragem de entrada
	 * @param kmEntrada Integer - quilometragem a ser atribuída
	 */
	public void setKmEntrada(Integer kmEntrada) {
		this.kmEntrada = kmEntrada;
	}

	/**
	 * Método de retorno do valor
	 * @return float - valor da locação
	 */
	public float getValor() {
		return valor;
	}
	/**
	 * Método para atribuir um valor a uma locação
	 * @param valor float - valor a ser atribuído
	 */
	public void setValor(float valor) {
		this.valor = valor;
	}

	/**
	 * Método para retornar a data de saída
	 * @return String - data de uma locação
	 */
	public String getDataSaida() {
		String dt = new SimpleDateFormat("dd/MM/yyyy").format(this.dataSaida.getTime());
		return dt;
	}
	/**
	 * Método para atribui uma data de saída
	 * @param dataSaida String - data a ser atribuída
	 */
	public void setDataSaida(String dataSaida) {
		//Quebra data no formato dd/mm/yyyy
		String s[] = dataSaida.split("/");
		if (s.length == 3)
			this.dataSaida.set(Integer.parseInt(s[2]), Integer.parseInt(s[1])-1, Integer.parseInt(s[0]));
	}

	/**
	 * Método de retorno da data de devolução
	 * @return String - data de devolução da locação
	 */
	public String getDataDevolucao() {
		return new SimpleDateFormat("dd/MM/yyyy").format(this.dataDevolucao.getTime());
	}

	/**
	 * Método para atribuir uma data de devolução
	 * @param dataDevolucao String -  data de devolução a ser atribuída
	 */
	public void setDataDevolucao(String dataDevolucao) {
		//Quebra data no formato dd/mm/yyyy
		String s[] = dataDevolucao.split("/");
		if (s.length == 3)
			this.dataDevolucao.set(Integer.parseInt(s[2]), Integer.parseInt(s[1])-1, Integer.parseInt(s[0]));
	}

	/**
	 * Método de retorno da previsão de dias
	 * @return Integer - Previsão de dias da locação
	 */
	public Integer getPrevisaoDias() {
		return previsaoDias;
	}
	/**
	 * Método para atribuir uma previsão de dias
	 * @param previsaoDias  Integer - Valor a ser atribuído
	 */
	public void setPrevisaoDias(Integer previsaoDias) {
		this.previsaoDias = previsaoDias;
	}
	/**
	 * Método para retorno do tipo da locação
	 * @return tipoLocacao String - Tipo da locação
	 */
	public String getTipoLocacao() {
		return tipoLocacao;
	}
	/**
	 * Método para atribuir um tipo à locação
	 * @param tipoLocacao String - tipo a ser atribuído
	 */
	public void setTipoLocacao(String tipoLocacao) {
		this.tipoLocacao = tipoLocacao;
	}
	/**
	 * Método que retorna o cliente da locação
	 * @return Cliente - Cliente que realizou a locação
	 */
	public Cliente getLocador() {
		return locador;
	}
	/**
	 * Método para atribuir um cliente a uma locação
	 * @param locador Cliente - Cliente que realizará a locação
	 */
	public void setLocador(Cliente locador) {
		this.locador = locador;
		if (this.locador != null)
			this.locador.addLocacao(this);
	}
	/**
	 * Método que retorna o veículo da locação
	 * @return Veiculo - Veiculo da locação
	 */
	public Veiculo getVeiculo() {
		return veiculo;
	}

	/**
	 * Método que atribui um veículo à locação
	 * @param veiculo Veiculo - Veiculo a ser atribuído à locação
	 */
	public void setVeiculo(Veiculo veiculo) {
		this.veiculo = veiculo;
		if (veiculo != null)
			veiculo.addLocacao(this);
	}

	/**
	 * Método que retorna os motoristas de determinada locação
	 * @return List<Motorista> - Vetor de motoristas da locação
	 */
	public List<Motorista> getMotoristas() {
		return motoristas;
	}

	/**
	 * Método para atribuir um motorista a uma locação
	 * @param parMotorista Motorista - Motorista a ser adicionado
	 */
	public void addMotorista (Motorista parMotorista){
		this.motoristas.add(parMotorista);
	}

	/**
	 * Método que remove um motorista de uma locação
	 * @param parMotorista Motorista - Motorista a ser removido
	 */
	public void removerMotorista (Motorista parMotorista) {
		this.motoristas.remove(parMotorista);
	}

	/**
	 * Método que remove todos motoristas de uma locação
	 */
	public void removerMotoristas () {
            while (!this.motoristas.isEmpty()) {
                this.motoristas.get(0).setLocacao(null);
            }
	}

	/**
	 * Método que fecha uma locação
	 * atribuindo uma quantia ao atributo de valor
	 * @return boolean - True se a locação foi fechada com sucesso
	 * False se não houve sucesso
	 */
	public boolean fecharLocacao() {
		this.setDataDevolucao(new SimpleDateFormat("dd/MM/yyyy").toString());
		Date sDate=null, fDate=null;
		try {
			sDate = new SimpleDateFormat("dd/MM/yyyy").parse(this.getDataDevolucao());
			fDate = new SimpleDateFormat("dd/MM/yyyy").parse(this.getDataSaida());
		}
		catch (ParseException e){System.out.println(e.getMessage());}
		if (sDate != null && fDate!=null) {
			int numDias = (int) ((sDate.getTime() - fDate.getTime()) / 1000 / 60 / 60 / 24);
			if (this.getVeiculo() != null) {
				float valorFinal = this.getVeiculo().getTipoVeiculo().getTaxaBase() * (numDias+1);
				if (this.getTipoLocacao().compareToIgnoreCase("q") == 0)
					valorFinal += this.getVeiculo().getTipoVeiculo().getPrecoQuilometro() * (this.getKmEntrada() - this.getKmSaida());
				this.setValor(valorFinal);
				this.removerMotoristas();
				return true;
			}
		}
		return false;
	}


	/**
	 * Método que retorna o identificador da locação
	 *
	 * @return String - Identificador a ser retornado
	 */
	@Override
	public String getIdentifier() {
		String idt = "[" + this.getVeiculo().getIdentifier();
		idt += FileManager.getIdtSeparator() + this.getDataSaida();
		idt += FileManager.getIdtSeparator() + this.getLocador().getIdentifier() + "]";

		return idt;
	}

	//Dados internos
	private Integer kmSaida;
	private Integer kmEntrada;
	private float valor;
	@Id
	@ManyToOne
	private Veiculo veiculo;
	@Id
	@Temporal(TemporalType.DATE)
	private Calendar dataSaida;
	@Temporal(TemporalType.DATE)
	private Calendar dataDevolucao;
	@Column(name="data_devolucao")
	private Integer previsaoDias;
	@Column(length=15)
	private String tipoLocacao;
	//Relacionamentos externos
	@OneToMany(mappedBy="locacao")
	private List<Motorista> motoristas;
	@ManyToOne
	private Cliente locador;
}

